package com.example.gfsquadwebviewproject.installerlibrary;


import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import androidx.core.content.FileProvider;
import com.example.gfsquadwebviewproject.BuildConfig;
import com.example.gfsquadwebviewproject.installerlibrary.utils.InstallerUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Created by wuhaojie on 2016/7/25 22:17.
 */
public class AutoInstaller extends Handler {
    String TAG = "AutoInstaller";

    static public boolean isDownLoading = false;//是否在下载中
    static public boolean isAccomplishDown = false;//是否成功下载

    private static volatile AutoInstaller mAutoInstaller;
    private Context context;
    private String mTempPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "AndroidApp";

    public enum MODE {
        ROOT_ONLY,
        AUTO_ONLY,
        BOTH
    }

    private MODE mMode = MODE.BOTH;

    private AutoInstaller(Context context) {
        this.context = context;
    }

    public static AutoInstaller getDefault(Context context) {
        if (mAutoInstaller == null) {
            synchronized (AutoInstaller.class) {
                if (mAutoInstaller == null) {
                    mAutoInstaller = new AutoInstaller(context);
                }
            }
        }
        return mAutoInstaller;
    }


    public interface OnStateChangedListener {
        void onStart();

        void onComplete();

        void onNeed2OpenService();

        void needPermission();
    }

    private OnStateChangedListener mOnStateChangedListener;

    public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
        mOnStateChangedListener = onStateChangedListener;
    }

    //申请权限
    private boolean installUseRoot(String filePath) {
        if (TextUtils.isEmpty(filePath))
            throw new IllegalArgumentException("Please check apk file path!");
        boolean result = false;
        Process process = null;
        OutputStream outputStream = null;
        BufferedReader errorStream = null;
        try {
            process = Runtime.getRuntime().exec("su");
            outputStream = process.getOutputStream();

            outputStream.write(("chmod 777 " + filePath+"\n").getBytes());

            String command = "pm install -r " + filePath + "\n";
            outputStream.write(command.getBytes());
            outputStream.flush();
            outputStream.write("exit\n".getBytes());
            outputStream.flush();
            process.waitFor();
            errorStream = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            StringBuilder msg = new StringBuilder();
            String line;
            while ((line = errorStream.readLine()) != null) {
                msg.append(line);
            }
            Log.d("Context", "install msg is " + msg);
            if (!msg.toString().contains("Failure")) {
                result = true;
            }
        } catch (Exception e) {
            Log.e("Context", e.getMessage(), e);
            result = false;
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (errorStream != null) {
                    errorStream.close();
                }
            } catch (IOException e) {
                outputStream = null;
                errorStream = null;
                process.destroy();
            }
        }
        return result;
    }

    public void installUseAS(String filePath) {
        try {
            // 存储空间
            if (permissionDenied()) {

                sendEmptyMessage(4);
                return;
            }

            // 允许安装应用
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                boolean b = context.getPackageManager().canRequestPackageInstalls();
                if (!b) {
                    sendEmptyMessage(4);
                    return;
                }
            }

            File file = new File(filePath);
            if (!file.exists()) {
                Log.e("Context", "apk file not exists, path: " + filePath);
                return;
            }
            Uri uri = Uri.fromFile(file);
            Intent intent = new Intent(Intent.ACTION_VIEW);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//            Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", file);
                Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, file);
                context.grantUriPermission(context.getPackageName(), contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
            } else {
                intent.setDataAndType(uri, "application/vnd.android.package-archive");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            if (context != null) {
                context.startActivity(intent);
            }
            if (!isAccessibilitySettingsOn(context)) {
                toAccessibilityService();
                sendEmptyMessage(3);
            }
        }
        catch (Exception e){
            Log.d(TAG,"installUseAS error:"+e);
        }
    }

    private boolean permissionDenied() {
        if (Build.VERSION.SDK_INT >= 23) {
            String[] permissions = {
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            };

            for (String str : permissions) {
                if (context.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    return true;
                }
            }
        }

        return false;
    }

    private void toAccessibilityService() {
        if (context!=null) {
            Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
        else {
            Log.d(TAG,"toAccessibilityService context is null");
        }
    }


    private boolean isAccessibilitySettingsOn(Context mContext) {
        int accessibilityEnabled = 0;
        final String service = mContext.getPackageName() + "/" + InstallAccessibilityService.class.getCanonicalName();
        try {
            accessibilityEnabled = Settings.Secure.getInt(
                    mContext.getApplicationContext().getContentResolver(),
                    Settings.Secure.ACCESSIBILITY_ENABLED);
            Log.v("Context", "accessibilityEnabled = " + accessibilityEnabled);
        } catch (Settings.SettingNotFoundException e) {
            Log.e("Context", "Error finding setting, default accessibility to not found: "
                    + e.getMessage());
        }
        TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':');

        if (accessibilityEnabled == 1) {
            Log.v("Context", "***ACCESSIBILITY IS ENABLED*** -----------------");
            String settingValue = Settings.Secure.getString(
                    mContext.getApplicationContext().getContentResolver(),
                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
            if (settingValue != null) {
                mStringColonSplitter.setString(settingValue);
                while (mStringColonSplitter.hasNext()) {
                    String accessibilityService = mStringColonSplitter.next();

                    Log.v("Context", "-------------- > accessibilityService :: " + accessibilityService + " " + service);
                    if (accessibilityService.equalsIgnoreCase(service)) {
                        Log.v("Context", "We've found the correct setting - accessibility is switched on!");
                        return true;
                    }
                }
            }
        } else {
            Log.v("Context", "***ACCESSIBILITY IS DISABLED***");
        }

        return false;
    }

    //安装
    public void install(final String filePath, final int type) {
        Log.d("Context","自动安装:"+filePath);
        //如果filePath为空或者后缀不是.apk
        if (TextUtils.isEmpty(filePath) || !filePath.endsWith(".apk")) {
            Log.d("Context","not a correct apk file path");
            throw new IllegalArgumentException("not a correct apk file path");
        }
        Log.d("Context","Thread mMode="+mMode);

        new Thread(new Runnable() {
            @Override
            public void run() {

                switch (mMode) {
                    case BOTH:
                        //查询是否有权限
                        if (!InstallerUtils.checkRooted() || !installUseRoot(filePath)) {
                            Log.d("Context","BOTH");
                            installUseAS(filePath);
                        }
                        else{
                            Log.d("Context","BOTHs");
                        }
                        break;
                    case ROOT_ONLY:
                        installUseRoot(filePath);
                        Log.d("Context","ROOT_ONLY");
                        break;
                    case AUTO_ONLY:
                        installUseAS(filePath);
                        Log.d("Context","AUTO_ONLY");
                }

                if (type==1) {
                    sendEmptyMessage(0);
                }
            }
        }).start();
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 0:
                if (mOnStateChangedListener != null) {
                    mOnStateChangedListener.onComplete();
                    Log.d("Context","下载完成");
                }
                break;
            case 1:
                if (mOnStateChangedListener != null) {
                    mOnStateChangedListener.onStart();
                    Log.d("Context","开始下载");
                }
                break;
            case 3:
                if (mOnStateChangedListener != null)
                    mOnStateChangedListener.onNeed2OpenService();
                break;
            case 4:
                if (mOnStateChangedListener != null) {
                    mOnStateChangedListener.needPermission();
                }
                break;
        }
    }

    public void install(File file) {
        if (file == null) {
            throw new IllegalArgumentException("file is null");
        }
        Log.d("Context","进行安装");
        install(file.getAbsolutePath(),1);
    }


    public void installFromUrl(final String httpUrl) {
        if (!isDownLoading) {
            isDownLoading = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    sendEmptyMessage(1);
                    //下载
                    File file = downLoadFile(httpUrl);

                    Log.d("Context", "安装地址：" + file.getAbsolutePath());
                    if (isAccomplishDown) {
                        install(file);
                    }
                    else {
                        Log.d("Context", "下载不完成，不安装");
                    }
                }
            }).start();
        }
    }

    //下载文件
    private File downLoadFile(String httpUrl) {
        Log.d("Context","downLoadFile");
        if (TextUtils.isEmpty(httpUrl)) {
//            isDownLoad = true;
            throw new IllegalArgumentException();
        }
        File file = new File(mTempPath);
        if (!file.exists()) {
            file.mkdirs();
        }
        file = new File(mTempPath + File.separator + "jysideboard.apk");
        Log.d("Context","下载地址："+file.getAbsolutePath());
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(httpUrl);
            connection = (HttpURLConnection) url.openConnection();
            if (connection instanceof HttpsURLConnection) {
                SSLContext sslContext = getSLLContext();
                if (sslContext != null) {
                    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
                    ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
                }
            }
            connection.setConnectTimeout(60 * 1000);
            connection.setReadTimeout(60 * 1000);

            connection.connect();
            inputStream = connection.getInputStream();
            Log.d("Context","下载大小："+inputStream.available());
            outputStream = new FileOutputStream(file);
            byte[] buffer = new byte[1024*1024*2];//不能超过16777216
            int len = 0;
            int sum = 0;
            while ((len = inputStream.read(buffer)) > 0) {
                sum = sum+len;
                Log.d("Context","下载大小："+sum);
                outputStream.write(buffer, 0, len);
            }
            isAccomplishDown = true;
            Log.d("Context","downLoadFile下载完成");
        } catch (Exception e) {
            isAccomplishDown = false;
            Log.d("Context","downLoadFile下载 error:"+e);
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
                if (outputStream != null)
                    outputStream.close();
                if (connection != null)
                    connection.disconnect();
            } catch (IOException e) {
                inputStream = null;
                outputStream = null;
            }
        }
        isDownLoading = false;
        return file;
    }

    private SSLContext getSLLContext() {
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslContext;
    }


}
